How to create NICE style graphics

The niceRplots package and cookbook make the process of creating publication-ready graphics in the NICE style a more reproducible process, as well as making it easier for people new to R to create graphics.

Within this cookbook, we will demonstrate how to use the functions included within the niceRplots package. We will also provide examples of plots that have been created in the NICE style.

Load the relevant packages

Before we can start making charts, we first need to load all of the relevant packages. We wont load every package here, just the ones that we will use the most often. It is good practice to limit the number of loaded packages to prevent masking conflicts. For this reason, we will often use double colons :: to access specific functions within a package (e.g. readr::read_csv()), rather than loading the full package using library(pkg).


How to style your charts

As an example we will create a simple bar chart using the iris dataset. We will first create a basic chart, and then add some additional formatting. We can see the two charts below with and without formatting.


We can now apply the NICE theme using the nice_gg_theme() function from the niceRplots package, specifying the base font for the plot to be of size 12. The nice_gg_theme() function alters several aspects of the chart to make it consistent with the NICE brand guidelines. These are as follows:

  • Fonts: changes the title font to Lora SemiBold, and all other text to Inter Regular.

  • Text scaling: applies a text hierarchy to the chart using relative text sizes. Changing the optional base_size argument will change the text size throughout the plot. Titles and subtitles will be automatically scaled relative to this base_size to maintain the text hierarchy. This is useful if you want to change the chart size, as all text can be simply adjusted by changing the base_size argument.

  • Colour scheme: changes line and text colours to be consistent with the NICE brand colour palette. This is particularly noticeable when creating faceted charts (shown later in cookbook). It should be noted that this will not add colour to the plotted data, this will still need to be added manually when creating the chart. For instance, a fill colour was added in the geom_col() argument in the above example.

  • Margins: adjusts the margins around the title, subtitle, and axis titles to give everything space to breathe.

  • Background: removes the panel background and borders.

  • Other: Applies major grid lines along the y-axis. This will be appropriate for most charts, but may need to be disabled in others by applying theme(panel.grid.major.y = ggplot2::element_blank())

The nice_gg_theme() function isn’t designed to modify every aspect of the chart, but to apply a general theme that will maintain consistency with the NICE style guide across all charts. Many aspects of the chart will still need to be modified manually. For example, in the below chart we may choose to apply an additional theme argument to remove the x-axis title.


How to finalise your charts

Once a plot has been created and styled using nice_gg_theme(), the next step is to apply the finalise_plot() function. This function will create a footer containing information on the data source, as well as adding the NICE logo to the bottom right. It will then left-align the title, subtitle and footer. The finalise_plot() function has 3 arguments:

  • plot_name: the name of the plot object, in the example below we have saved ours as iris_bar_themed.

  • source_name: the source of the underlying data. We have used data from the iris dataset.

  • logo: this will determine whether the NICE logo is included in the footer. It can have a value of “NICE” to include the logo, or “none” to leave it blank.


How to save your finalised plots

After applying the finalise_plot() function, the chart can be saved using the ggsave() function.


Static charts using ggplot2

The sections below provide examples of how to make different types of static chart using the ggplot2 package. These will demonstrate how to format different charts and apply the NICE theme. For some examples we will continue to use R’s built in iris dataset. For others we will use data on the monthly Sub-ICB location level prescribing of 5 direct oral anticoagulants (DOACS) in England between February 2017 and January 2022. This was downloaded from OpenPrescribing.net.


Histogram


Bar chart


Line chart


Scatter plot


Faceted chart


Choropleth map (heatmap)

Prepare .geoJSON files

In the example below we will prepare a choropleth map of Apixaban prescribing across Sub-ICB locations in 2021. To prepare this chart we need two files, a dataframe containing the data we want to visualise, and a dataframe containing the shapes for our relevant health geographies. For these examples we will use the doacs_df and sub_icb_shapes_2022 files that come built into the niceRplots package.

There will be many situations where you will want to visualise data across other geographies. The files containing shapes for other geographies can be downloaded in .geoJSON format from the Office for National Statistics (ONS) Open Geography Portal.

These .geoJSON files from ONS come with different levels of accuracy, with more accurate files having a larger file size. These files can be distinguished by the letters at the end of the file name (BFC > BFE > BCG > BUC). We recommend downloading the smallest .geoJSON file (BUC), as this will greatly increase the speed of plotting. In some cases only a very detailed file will be available. In these cases you will need to simplify the file using the rmapshaper package.

The code below provides examples of how to load in a .geoJSON file as a dataframe, how to load and simplify a file using the rmapshaper package, and how to combine multiple shapes into a single shape (useful to give the map a darker outside boundary).

Now that we have prepared our .geoJSON files, we can go ahead and prepare our choropleth map.


Interactive charts

Choropleth map (Leaflet)

# Declare location
here::i_am("R/plotly_theme.R")
## here() starts at C:/Users/VKam/Documents/R_work/niceRplots

Interactive charts

Plotly

Styling a Plotly chart

# Load NICE colours
load(here::here("data", "nice_colours_full.rda"))

# Create basic bar chart (left)
plotly_iris_bar <- plot_ly(iris_bar_df,
                    x = ~Species,
                    y = ~Sepal_Width,
                    type = "bar")

# Create formatted chart (right)
plotly_iris_bar_formatted <- plot_ly(iris_bar_df,
                    x = ~Species,
                    y = ~Sepal_Width,
                    type = "bar",
                    marker = list(color = nice_colours_full[["bold_teal_100"]],
                                  line = list(color = nice_colours_full[['black_100']], width = 1.5)))

plotly_iris_bar
plotly_iris_bar_formatted
# fig.show = "hold" not working for Plotly?
plotly_iris_bar_themed <- plotly_iris_bar_formatted %>% 
  nice_plotly_theme(chart_type = "vertical_bar",
             x_title = "Species",
             y_title = "Sepal Width")

Formatted chart headline title

Figure x. Formatted chart statistical title

Alt text (text description of message chart is showing. Mark chart as decorative)
Source: []
Download the data for Figure x (CSV, 5.0KB).

How to save your plot

To download the plot as a static PNG image, click on the camera icon at the top right of the plot.

Saving in other file formats (e.g. .svg or .jpg) is more complicated and requires installation of another piece of software. Read the Plotly documentation on exporting graphs as static images in R.

Tooltip

Chart types

Histogram

Use chart_type = “horizontal_bar” for histograms.

# Create chart
plotly_hist <- iris %>%
  plot_ly(x = ~Sepal.Width,
          color = ~Species,
          # Use NICE colours - remove colour names so it maps correctly
          colors = unname(nice_palettes[["discrete"]][1:3]),
          type = "histogram",
          # Black outline for bars
          marker = list(line = list(color = nice_colours_full[['black_100']], width = 1.5)),
          # Set bin width
          xbins = list(size = 0.2,
                       start = 1.9,
                       end = 4.5)) %>% 
  # Stack bars
  layout(barmode = "stack") %>% 
  # Add NICE theme and set axis titles
  nice_plotly_theme(chart_type = "vertical_bar",
             x_title = "Sepal width",
             y_title = "Frequency")

plotly_hist
# Category order differs from ggplot but no big difference

Bar chart

Vertical bar chart

Use chart_type = “vertical_bar”.

# Create chart
plotly_vbar_chart <- bar_df %>%
  # Reorder chemical factor levels in decreasing order of items
  mutate(chemical = reorder(chemical, -items)) %>% 
  plot_ly(x = ~chemical,
          y = ~items,
          type = "bar",
          # Bold teal bars with black outline
          marker = list(color = nice_colours_full[["bold_teal_100"]],
                        line = list(color = nice_colours_full[['black_100']], width = 1.5))) %>% 
  # Add NICE theme and set axis titles
  nice_plotly_theme(chart_type = "vertical_bar",
             x_title = "",
             y_title = "Dispensed items (millions)")

Apixaban was the most prescribed DOAC in 2021

Figure x. Total DOAC medicines dispensed in primary care in England, 2020

Horizontal bar chart

Use chart_type = “horizontal_bar”.

# Create chart
plotly_vbar_chart <- bar_df %>%
  # Reorder chemical factor levels in decreasing order of items
  mutate(chemical = reorder(chemical, items)) %>% 
  plot_ly(x = ~items,
          y = ~chemical,
          type = "bar",
          # Make horizontal
          orientation = "h",
          # Bold teal bars with black outline
          marker = list(color = nice_colours_full[["bold_teal_100"]],
                        line = list(color = nice_colours_full[['black_100']], width = 1.5))) %>% 
  # Add NICE theme and set axis titles
  nice_plotly_theme(chart_type = "horizontal_bar",
             x_title = "Dispensed items (millions)",
             y_title = "")

plotly_vbar_chart
Line chart

Use chart_type = “line”.

# Create chart
plotly_line_chart <- line_df %>%
  plot_ly(x = ~date,
          y = ~items,
          type = "scatter",
          # Line with marker dot at each data point
          mode = "lines+markers",
          # Make line and dots teal
          marker = list(color = nice_colours_full[["bold_teal_100"]])) %>%
  # Add the vertical dashed line to show lockdown date. Added this before plotting the 
  # data so that it sits on a layer behind the line and points
  add_lines(x = as.Date("2020-03-01"),
            y = ~c(0, max(items)),
            line = list(dash = "dash",
                        color = "#000000",
                        width = 1.5),
            # Don't inherit properties of previous trace
            inherit = FALSE) %>% 
  layout(showlegend = FALSE,
         xaxis = list(type = "date", # Specify x axis is date
                      # Show x axis ticks
                      ticks = "outside", 
                      # Format ticks as abbreviated month name and full year, e.g. Jan 2018
                      tickformat = "%b\n%Y",
                      # Set first tick
                      tick0 = "2017-07-01",
                      # Tick every 6 months
                      dtick = "M6"),
          # Y axis ticks with commas as thousands separators
         yaxis = list(tickformat = ",",
                      range = ~c(0, max(items)+10000)),
         annotations = list(x = as.Date("2020-03-01"),
                            xshift = -60,
                            y = 180000,
                            text = "National lockdown\non 23 March",
                            xref = "x",
                            yref = "y",
                            showarrow = FALSE, 
                            align = "right")) %>% 
  # Add NICE theme and set axis titles
  nice_plotly_theme(chart_type = "line",
             x_title = "",
             y_title = "Dispensed items",
             # Don't pad the axes, as ticks shown. Do not want gap between axis line and ticks
             pad_axes = FALSE)

Edoxaban prescribing has increased since 2017
Figure x. Edoxaban prescribing in England, 2017-2022

Scatter plot
# Create chart
plotly_scatter_chart <- scatter_df %>%
  plot_ly(x = ~total_list_size,
          y = ~items,
          type = "scatter",
          mode = "markers",
          marker = list(color = nice_colours_full[["bold_teal_100"]])
          ) %>% 
  layout(showlegend = FALSE,
         # Axis ticks with commas as thousands separators
         xaxis = list(tickformat = ","),
         yaxis = list(tickformat = ",")) %>% 
  # Add NICE theme and set axis titles
  nice_plotly_theme(chart_type = "scatter",
             x_title = "Primary care list size (x1000)",
             y_title = "Dispensed items",
             # Don't pad the axes, as ticks shown. Do not want gap between axis line and ticks
             pad_axes = FALSE)

Apixaban prescribing
Items of apixaban dispensed in primary care compared to sub-ICB location list size, July 2021

Faceted charts

The easiest way to make faceted charts in Plotly is to make it in ggplot and then convert it into a Plotly chart using the function ggplotly.

# Create chart
ggplotly(facet_chart)
facet_template <- function(i) {

  chemicals <- unique(facet_df$chemical)
  
  facet_df %>% 
    filter(chemical == chemicals[[i]]) %>% 
    plot_ly(x = ~date,
            y = ~items,
            type = "scatter",
            mode = "lines+markers",
            marker = list(color = nice_colours[[i]]),
            name = chemicals[[i]]) %>% 
    layout(showlegend = FALSE,
           xaxis = list(type = "date", # Specify x axis is date
                        # Show x axis ticks
                        ticks = "outside", 
                        # Format ticks as abbreviated month name and full year, e.g. Jan 2018
                        tickformat = "%b\n%Y",
                        # Outline box around plot
                        showline = TRUE,
                        mirror = "all"),
           yaxis = list(showline = TRUE,
                        mirror = "all"),
           # Subplot titles
           annotations = list(xref = 'paper',
                             yref = 'paper',
                             yanchor = 'bottom',
                             xanchor = 'center',
                             align = 'center',
                             x = .5,
                             y = 1,
                             showarrow = FALSE,
                             text = chemicals[[i]],
                             bgcolor = nice_colours[[1]],
                             font = list(color = "#ffffff"))) %>% 
    nice_plotly_theme(chart_type = "line",
             x_title = "",
             y_title = "Dispensed items (thousands)",
             # Don't pad the axes, as ticks shown. Do not want gap between axis line and ticks
             pad_axes = FALSE)
}

plot_list <- map(1:length(unique(facet_df$chemical)), facet_template)

subplot(plot_list, shareX = TRUE, shareY = TRUE)